package com.orderplus.opshop.common.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 反射给对象赋值
 *
 * @author 聂维
 */
@SuppressWarnings("rawtypes")
public class ReflectForAttributeUtil {
	/**
	 * 正则表达式 用于匹配属性的第一个字母 {@value [a-zA-Z]}
	 **/
	private static final String REGEX = "[a-zA-Z]";

	/**
	 * @param src      被复制对象(必须是public类)
	 * @param srcClass 被复制对象类名
	 * @param dest     接收对象(有初始化,而且必须是public类)
	 * @throws Exception
	 */
	public static void copyObjectAttrribute(Object src, Class<?> srcClass, Object dest) throws Exception {
		for (Field f : src.getClass().getDeclaredFields()) {
			PropertyDescriptor pd = new PropertyDescriptor(f.getName(), srcClass);
			Method getMethod = pd.getReadMethod();
			Object value = getMethod.invoke(src);
			if (!(value instanceof List)) {
				setAttrributeValue(dest, f.getName(), value);
			}
		}
	}

	/**
	 * @param src  源对象
	 * @param dest 目标待赋值对象
	 * @throws Exception
	 * @since 推荐使用, 效果更好, 更全面执行
	 */
	public static void copyObjectAttrribute(Object src, Object dest) throws Exception {
		for (Field f : src.getClass().getDeclaredFields()) {
			PropertyDescriptor pd = new PropertyDescriptor(f.getName(), src.getClass());
			Method getMethod = pd.getReadMethod();
			Object value = getMethod.invoke(src);
			PropertyDescriptor pdt = null;
			try {
				pdt = new PropertyDescriptor(f.getName(), dest.getClass());
				Method setMethod = pdt.getWriteMethod();
				setMethod.invoke(dest, value);
			} catch (Exception e) {
				System.out.println("dest没有该属性时候异常 " + e);
				continue;
			}
		}
	}

	/**
	 * 自定义可以扩展
	 *
	 * @param obj       接收对象(有初始化,执行类可以获得访问权限即可)
	 * @param attribute 对象的属性名
	 * @param value     属性值
	 */
	public static void setAttrributeValue(Object obj, String attribute, Object value) {
		String method_name = convertToMethodName(attribute, obj.getClass(), true);
		Method[] methods = obj.getClass().getMethods();
		for (Method method : methods) {
			/**
			 *     因为这里只是调用bean中属性的set方法，属性名称不能重复
			 * 所以set方法也不会重复，所以就直接用方法名称去锁定一个方法
			 * （注：在java中，锁定一个方法的条件是方法名及参数）
			 * **/
			if (method.getName().equals(method_name)) {
				Class[] parameterC = method.getParameterTypes();
				try {
					/**如果是基本数据类型时（如int、float、double、byte、char、boolean）
					 * 需要先将Object转换成相应的封装类之后再转换成对应的基本数据类型
					 * 否则会报 ClassCastException**/
					if (parameterC[0] == int.class) {
						method.invoke(obj, ((Integer) value).intValue());
						break;
					} else if (parameterC[0] == float.class) {
						method.invoke(obj, ((Float) value).floatValue());
						break;
					} else if (parameterC[0] == double.class) {
						method.invoke(obj, ((Double) value).doubleValue());
						break;
					} else if (parameterC[0] == byte.class) {
						method.invoke(obj, ((Byte) value).byteValue());
						break;
					} else if (parameterC[0] == char.class) {
						method.invoke(obj, ((Character) value).charValue());
						break;
					} else if (parameterC[0] == boolean.class) {
						method.invoke(obj, ((Boolean) value).booleanValue());
						break;
					} else {
						method.invoke(obj, parameterC[0].cast(value));
						break;
					}
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				} catch (SecurityException e) {
					e.printStackTrace();
				}
			}
		}
	}


	/**
	 * @param obj       接收对象(有初始化,执行类可以获得访问权限即可)
	 * @param attribute 对象的属性名
	 * @param value     属性值
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 */
	public static void setAttrributeValueNo2(Object obj, String attribute, Object value) throws NoSuchMethodException, SecurityException {
		if (null == value) {
			return;
		}
		String method_name = convertToMethodName(attribute, obj.getClass(), true);
		Class<?> clas = obj.getClass();
		System.out.println(method_name + " -- method_name ------class is " + clas);
		System.out.println("value.getClass() is " + value.getClass());
		//Method[] methods = obj.getClass().getMethods();
		Method method = clas.getDeclaredMethod(method_name, value.getClass());
		if (null == method) {
			return;
		}
		Class[] parameterC = method.getParameterTypes();
		try {
			/**
			 * 如果是基本数据类型时（如int、float、double、byte、char、boolean）
			 * 需要先将Object转换成相应的封装类之后再转换成对应的基本数据类型 否则会报 ClassCastException
			 **/
			if (parameterC[0] == int.class) {
				method.invoke(obj, ((Integer) value).intValue());

			} else if (parameterC[0] == float.class) {
				method.invoke(obj, ((Float) value).floatValue());

			} else if (parameterC[0] == double.class) {
				method.invoke(obj, ((Double) value).doubleValue());

			} else if (parameterC[0] == byte.class) {
				method.invoke(obj, ((Byte) value).byteValue());

			} else if (parameterC[0] == char.class) {
				method.invoke(obj, ((Character) value).charValue());

			} else if (parameterC[0] == boolean.class) {
				method.invoke(obj, ((Boolean) value).booleanValue());

			} else {
				method.invoke(obj, parameterC[0].cast(value));

			}
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}

	}

	private static String convertToMethodName(String attribute, Class objClass, boolean isSet) {
		/** 通过正则表达式来匹配第一个字符 **/
		Pattern p = Pattern.compile(REGEX);
		Matcher m = p.matcher(attribute);
		StringBuilder sb = new StringBuilder();
		/** 如果是set方法名称 **/
		if (isSet) {
			sb.append("set");
		} else {
			/** get方法名称 **/
			try {
				Field attributeField = objClass.getDeclaredField(attribute);
				/** 如果类型为boolean **/
				if (attributeField.getType() == boolean.class || attributeField.getType() == Boolean.class) {
					sb.append("is");
				} else {
					sb.append("get");
				}
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			}
		}
		/** 针对以下划线开头的属性 **/
		if (attribute.charAt(0) != '_' && m.find()) {
			sb.append(m.replaceFirst(m.group().toUpperCase()));
		} else {
			sb.append(attribute);
		}
		return sb.toString();
	}


	public static Object getAttrributeValue(Object obj, String attribute) {
		String methodName = convertToMethodName(attribute, obj.getClass(), false);
		Object value = null;
		try {
			/** 由于get方法没有参数且唯一，所以直接通过方法名称锁定方法 **/
			Method methods = obj.getClass().getDeclaredMethod(methodName);
			if (methods != null) {
				value = methods.invoke(obj);
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return value;
	}

	public static Class[] getClassArrayByName(String className) throws ClassNotFoundException {
		String[] arrayClassType = null;
		if (ValueUtil.isNotEmpty(className)) {
			arrayClassType = className.split(",");
		} else {
			return null;
		}

		Class[] classesType = new Class[arrayClassType.length];

		for (int i = 0; i < arrayClassType.length; i++) {
			classesType[i] = Class.forName(arrayClassType[i]);

		}
		return classesType;
	}

}
